#!/usr/bin/env python
# -*- coding:utf-8 -*-
import sys

sys.path.append('..')
from common_utils import CBBCommonUtils

aliases_blacklist = ['games-root', 'ingres-root', 'system-root', 'toor-root', 'uucp-root', 'manager-root',
                     'dumper-root', 'operator-root', 'decode-root', 'root-marc']


def get_plugin_info():
    plugin_info = {
        "name": "centos_access_control_013 Disable_unnecessary_account_aliases",
        "plugin_id": "centos_access_control_013",
        "plugin_type": "Access Control",
        "info": "Check and disable unnecessary account aliases",
        "level": "C",
        "module": "Safety reinforcement",
        "author": "fanyi",
        "keyword": "Safety reinforcement",
        "configable": "false"
    }
    return plugin_info


logger = None
cur_user = None
cur_module = None
cur_task = None


def set_plugin_logger(setter, user, module, task, *args, **kwargs):
    global logger, cur_user, cur_module, cur_task
    logger = setter
    cur_user = user
    cur_module = module
    cur_task = task


# 扫描函数
def scan(ip, sys_user, sys_pwd, flag=0):
    des_list = []
    error_count = 0
    # 别名情况记录及有无风险的标记
    d_flag = 0
    aliases_status = []
    logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "Scan Start.")
    # 检查别名状态
    for i, value in enumerate(aliases_blacklist):
        aliases_value = value.split("-")
        cmd = "cat /etc/aliases | grep -v \"#\" | grep " + aliases_value[0] + " | grep " + aliases_value[1]
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
        if not result and len(output) == 0:
            aliases_status.append("safe")
        elif not result and len(output) != 0:
            output[0] = output[0].replace("\n", "")
            aliases_status.append(output[0])
            d_flag = 1
            des_list.append(output[0].replace("\t", " "))
            logger.debug_warning(cur_user, cur_module, cur_task + '_Scan', '', output[0].replace("\t", " "))
        else:
            aliases_status.append("safe")
    if d_flag == 0:
        des_list.append("All Safe")
        logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "All Safe.")
    des_list.append("Scan Complete.")
    logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "Scan Complete.")
    # 是否加固
    if flag == 1 and d_flag == 1:
        reinforce_des, reinforce_err = reinforce(ip, sys_user, sys_pwd, aliases_status)
        if reinforce_err == 0:
            error_count = 0
            des_list.extend(reinforce_des)
        else:
            error_count += 1
            des_list.extend(reinforce_des)
    return des_list, error_count


# 加固函数
def reinforce(ip, sys_user, sys_pwd, aliases_status):
    des_list = []
    error_count = 0
    # 别名状态记录及有无风险的标记
    flag = 0
    logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Reinforce Start.")
    # 检查是否存在可能被覆盖的备份文件
    check_cmd = "ls /etc | grep aliases.`date +%Y-%m-%d`"
    check_result, check_output = CBBCommonUtils.cbb_run_cmd(ip, check_cmd, username=sys_user, passwd=sys_pwd)
    if not check_result and len(check_output) != 0:
        result = []
    else:
        # 备份文件，文件名中的RD为RootDisabled缩写，为了针对功能点控制备份文件用，避免备份冲突
        cmd = "cp /etc/aliases /etc/aliases.`date +%Y-%m-%d`"
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
    if not result:
        # 检查是否备份成功
        check_cmd = "ls /etc | grep aliases.`date +%Y-%m-%d`"
        check_result, check_output = CBBCommonUtils.cbb_run_cmd(ip, check_cmd, username=sys_user, passwd=sys_pwd)
        if not check_result and len(check_output) != 0:
            logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Backup Succeed.")
        else:
            error_count += 1
            backup_check_des = "Backup check FAILED."
            des_list.append(backup_check_des)
            logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', backup_check_des)
            return des_list, error_count
    else:
        error_count += 1
        des_list.append("Backup Failed.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', "Backup Failed.")
        return des_list, error_count
    # 加固
    for i, value in enumerate(aliases_status):
        if value != "safe":
            safe_cmd = "sed -i \'/" + aliases_status[i] + "/c #" + aliases_status[i] + "\' /etc/aliases"
            result, output = CBBCommonUtils.cbb_run_cmd(ip, safe_cmd, username=sys_user, passwd=sys_pwd)
            if len(result) != 0:
                error_count += 1
                des_list.append("Reinforce Error.")
                logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', "Reinforce Error.")
                # 加固失败，回滚
                rollback_des, rollback_err = rollback(ip, sys_user, sys_pwd)
                if rollback_err == 0:
                    des_list.extend(rollback_des)
                else:
                    error_count += 1
                    des_list.extend(rollback_des)
                return des_list, error_count
    # 初始化
    flag = 0
    # 检查加固结果
    for i, value in enumerate(aliases_blacklist):
        aliases_value = value.split("-")
        cmd = "cat /etc/aliases | grep -v \"#\" | grep " + aliases_value[0] + " | grep " + aliases_value[1]
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
        if not result and len(output) != 0:
            flag = 1
    # 记录和返回
    if flag == 0:
        des_list.append("Reinforce Complete.")
        logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Reinforce Complete.")
        return des_list, error_count
    else:
        error_count += 1
        des_list.append("Reinforce Failed.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', "Reinforce Failed.")
        # 加固失败，回滚
        rollback_des, rollback_err = rollback(ip, sys_user, sys_pwd)
        if rollback_err == 0:
            des_list.extend(rollback_des)
        else:
            error_count += 1
            des_list.extend(rollback_des)
        return des_list, error_count


# 回滚函数
def rollback(ip, sys_user, sys_pwd):
    des_list = []
    error_count = 0
    logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Rollback Start.")
    # 查找备份文件，此处的查找支持多备份文件的查找（结果会按时间顺序排序），并默认回滚最新一次备份的内容，可以连续多次回滚
    grep_cmd = "ls /etc/ | grep aliases..*"
    result, output = CBBCommonUtils.cbb_run_cmd(ip, grep_cmd, username=sys_user, passwd=sys_pwd)
    if not result and len(output) != 0:
        target = output[len(output) - 1].replace("\n", "")
    else:
        error_count = -1
        des_list.append("Backup file NOT FOUND.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', "Backup file not found.")
        return des_list, error_count
    # 回滚文件
    cmd = "/bin/cp -rf /etc/" + target + " /etc/aliases"
    result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
    if not result:
        logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Rollback Succeed.")
        del_cmd = "rm -rf /etc/" + target
        # 删除对应的备份文件
        result, output = CBBCommonUtils.cbb_run_cmd(ip, del_cmd, username=sys_user, passwd=sys_pwd)
        if not result:
            del_des = "Backup file deleted. Target is {}.".format(target)
            logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', del_des)
        else:
            error_count += 1
            del_des = "Backup file delete FAILED."
            des_list.append(del_des)
            logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', del_des)
            return des_list, error_count
    else:
        error_count += 1
        des = "Rollback FAILED, please retry."
        des_list.append(des)
        logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', des)
        return des_list, error_count
    des_list.append("Rollback Complete.")
    logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Rollback Complete.")
    return des_list, error_count


# 扫描函数
def scanMail(ip, sys_user, sys_pwd, flag=0):
    des_list = []
    error_count = 0
    # 别名情况记录及有无风险的标记
    d_flag = 0
    aliases_status = []
    logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "Mail Scan Start.")
    # 检查别名状态
    for i, value in enumerate(aliases_blacklist):
        aliases_value = value.split("-")
        cmd = "cat /etc/mail/aliases | grep -v \"#\" | grep " + aliases_value[0] + " | grep " + aliases_value[1]
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
        if not result and len(output) == 0:
            aliases_status.append("safe")
        elif not result and len(output) != 0:
            output[0] = output[0].replace("\n", "")
            aliases_status.append(output[0])
            d_flag = 1
            des_list.append(output[0].replace("\t", " "))
            logger.debug_warning(cur_user, cur_module, cur_task + '_Scan', '', output[0].replace("\t", " "))
        else:
            aliases_status.append("safe")
    if d_flag == 0:
        des_list.append("All Safe")
        logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "All Safe.")
    des_list.append("Mail Scan Complete.")
    logger.debug_info(cur_user, cur_module, cur_task + '_Scan', '', "Mail Scan Complete.")
    # 是否加固
    if flag == 1 and d_flag == 1:
        reinforce_des, reinforce_err = reinforceMail(ip, sys_user, sys_pwd, aliases_status)
        if reinforce_err == 0:
            error_count = 0
            des_list.extend(reinforce_des)
        else:
            error_count += 1
            des_list.extend(reinforce_des)
    return des_list, error_count


# 加固函数
def reinforceMail(ip, sys_user, sys_pwd, aliases_status):
    des_list = []
    error_count = 0
    # 别名状态记录及有无风险的标记
    flag = 0
    logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Mail Reinforce Start.")
    # 检查是否存在可能被覆盖的备份文件
    check_cmd = "ls /etc/mail | grep aliases.`date +%Y-%m-%d`"
    check_result, check_output = CBBCommonUtils.cbb_run_cmd(ip, check_cmd, username=sys_user, passwd=sys_pwd)
    if not check_result and len(check_output) != 0:
        result = []
    else:
        # 备份文件，文件名中的RD为RootDisabled缩写，为了针对功能点控制备份文件用，避免备份冲突
        cmd = "cp /etc/mail/aliases /etc/aliases.`date +%Y-%m-%d`"
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
    if not result:
        # 检查是否备份成功
        check_cmd = "ls /etc/mail | grep aliases.`date +%Y-%m-%d`"
        check_result, check_output = CBBCommonUtils.cbb_run_cmd(ip, check_cmd, username=sys_user, passwd=sys_pwd)
        if not check_result and len(check_output) != 0:
            logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Backup Succeed.")
        else:
            error_count += 1
            backup_check_des = "Backup check FAILED."
            des_list.append(backup_check_des)
            logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', backup_check_des)
            return des_list, error_count
    else:
        error_count += 1
        des_list.append("Backup Failed.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', "Backup Failed.")
        return des_list, error_count
    # 加固
    for i, value in enumerate(aliases_status):
        if value != "safe":
            safe_cmd = "sed -i \'/" + aliases_status[i] + "/c #" + aliases_status[i] + "\' /etc/mail/aliases"
            result, output = CBBCommonUtils.cbb_run_cmd(ip, safe_cmd, username=sys_user, passwd=sys_pwd)
            if len(result) != 0:
                error_count += 1
                des_list.append("Reinforce Error.")
                logger.debug_error(cur_user, cur_module, cur_task + '_Reinforce', '', "Mail Reinforce Error.")
                # 加固失败，回滚
                rollback_des, rollback_err = rollbackMail(ip, sys_user, sys_pwd)
                if rollback_err == 0:
                    des_list.extend(rollback_des)
                else:
                    error_count += 1
                    des_list.extend(rollback_des)
                return des_list, error_count
    # 初始化
    flag = 0
    # 检查加固结果
    for i, value in enumerate(aliases_blacklist):
        aliases_value = value.split("-")
        cmd = "cat /etc/mail/aliases | grep -v \"#\" | grep " + aliases_value[0] + " | grep " + aliases_value[1]
        result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
        if not result and len(output) != 0:
            flag = 1
    # 记录和返回
    if flag == 0:
        des_list.append("Reinforce Complete.")
        logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Mail Reinforce Complete.")
        return des_list, error_count
    else:
        error_count += 1
        des_list.append("Reinforce Failed.")
        logger.debug_info(cur_user, cur_module, cur_task + '_Reinforce', '', "Mail Reinforce Failed.")
        # 加固失败，回滚
        rollback_des, rollback_err = rollbackMail(ip, sys_user, sys_pwd)
        if rollback_err == 0:
            des_list.extend(rollback_des)
        else:
            error_count += 1
            des_list.extend(rollback_des)
        return des_list, error_count


# 回滚函数
def rollbackMail(ip, sys_user, sys_pwd):
    des_list = []
    error_count = 0
    logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Mail Rollback Start.")
    # 查找备份文件，此处的查找支持多备份文件的查找（结果会按时间顺序排序），并默认回滚最新一次备份的内容，可以连续多次回滚
    grep_cmd = "ls /etc/mail/ | grep aliases..*"
    result, output = CBBCommonUtils.cbb_run_cmd(ip, grep_cmd, username=sys_user, passwd=sys_pwd)
    if not result and len(output) != 0:
        target = output[len(output) - 1].replace("\n", "")
    else:
        error_count = -1
        des_list.append("Backup file NOT FOUND.")
        logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', "Mail Backup file not found.")
        return des_list, error_count
    # 回滚文件
    cmd = "/bin/cp -rf /etc/mail/" + target + " /etc/mail/aliases"
    result, output = CBBCommonUtils.cbb_run_cmd(ip, cmd, username=sys_user, passwd=sys_pwd)
    if not result:
        logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Mail Rollback Succeed.")
        del_cmd = "rm -rf /etc/mail/" + target
        # 删除对应的备份文件
        result, output = CBBCommonUtils.cbb_run_cmd(ip, del_cmd, username=sys_user, passwd=sys_pwd)
        if not result:
            del_des = "Backup file deleted. Target is {}.".format(target)
            logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', del_des)
        else:
            error_count += 1
            del_des = "Backup file delete FAILED."
            des_list.append(del_des)
            logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', del_des)
            return des_list, error_count
    else:
        error_count += 1
        des = "Rollback FAILED, please retry."
        des_list.append(des)
        logger.debug_error(cur_user, cur_module, cur_task + '_Rollback', '', des)
        return des_list, error_count
    des_list.append("Rollback Complete.")
    logger.debug_info(cur_user, cur_module, cur_task + '_Rollback', '', "Mail Rollback Complete.")
    return des_list, error_count


def check(ip, *args, **kwargs):
    sys_user = kwargs.get("system_user")
    sys_pwd = kwargs.get("system_pwd")
    comm = kwargs.get("command")
    try:
        des_list = []
        logger.debug_info(cur_user, cur_module, cur_task + '_Check', '', "centos_access_control_013 Start")
        if comm == 1:
            des_scan, error_scan = scan(ip, sys_user, sys_pwd, flag=0)
            des_list.extend(des_scan)
            des_scan_mail, error_scan_mail = scanMail(ip, sys_user, sys_pwd, flag=0)
            des_list.extend(des_scan_mail)
            step_error = int(error_scan) + int(error_scan_mail)
        elif comm == 2:
            des_reinforce, error_reinforce = scan(ip, sys_user, sys_pwd, flag=1)
            des_list.extend(des_reinforce)
            des_reinforce_mail, error_reinforce_mail = scanMail(ip, sys_user, sys_pwd, flag=1)
            des_list.extend(des_reinforce_mail)
            step_error = int(error_reinforce) + int(error_reinforce_mail)
        elif comm == 3:
            des_rollback, error_rollback = rollback(ip, sys_user, sys_pwd)
            des_list.extend(des_rollback)
            des_rollback_mail, error_rollback_mail = rollbackMail(ip, sys_user, sys_pwd)
            des_list.extend(des_rollback_mail)
            step_error = int(error_rollback) + int(error_rollback_mail)
        else:
            return {"code": 3, "count": 0, "des": ['command must be 1/2/3']}
        logger.debug_info(cur_user, cur_module, cur_task + '_Check', '', "centos_access_control_013 Complete")
        if step_error == 0:
            code = 0
        elif step_error <= -1:
            code = 2
        else:
            code = 1
        return {"code": code, "count": step_error, "des": des_list}
    except Exception as er:
        code = 1
        des = ["ERROR:", str(er)]
        logger.debug_error(cur_user, cur_module, cur_task + '_Check', '', des)
        return {"code": code, "count": 0, "des": des}

# check(ip="100.2.91.150", system_user="root", system_pwd="admin", command=0, flag=0)
